package cs2114.alarmclock;

import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * // -------------------------------------------------------------------------
/**
 *  a Deque implementation of a LinkedList.
 *
 *  @author Joe Acanfora
 *  @version Nov 16, 2011
 *  @param <Item> data held by links.
 */
public class Deque<Item>
{
    //------------Fields--------------------------
    // sentenial Links
    private Link<Item> head;
    private Link<Item> tail;
    private int size;

    /**
     * Constructor for the Deque.
     */
    public Deque()
    {
        head = new Link<Item>(null);
        tail = new Link<Item>(null);
        head.join(tail);
        size = 0;
    }
    /**
     * Adds a link to the rear of the list.
     * @param value  new data to be added to the list.
     */
    public void enqueueAtRear(Item value)
    {
        Link<Item> newLink = new Link<Item>(value);
        Link<Item> temp = tail.previous();
        temp.split();
        temp.join(newLink);
        newLink.join(tail);
        size++;
    }
    /**
     * Adds a link to the front of the list.
     * @param value  new data to be added to the list.
     */
    public void enqueueAtFront(Item value)
    {
        Link<Item> newLink = new Link<Item>(value);
        Link<Item> temp = head.next();
        head.split();
        head.join(newLink);
        newLink.join(temp);
        size++;
    }
    /**
     * Removes and returns link from the front.
     * @return data from the front of the list.
     */
    public Item dequeueAtFront()
    {
        if (!(size > 0))
        {
            throw new NoSuchElementException("no such element");
        }

        Link<Item> front = head.next();
        Item data = front.getData();
        Link<Item> temp = front.next();
        front.split();
        head.split();
        front.join(temp);
        size--;
        return data;
    }
    /**
     * Returns the data from the front without changing the set.
     * @return Item  the data from the front.
     */
    public Item peek()
    {
        if (size == 0)
        {
            throw new NoSuchElementException("no such element");
        }
        return head.next().getData();
    }
    /**
     * Getter method for the size field, which stores the number of elements
     * currently stored in this Queue.
     * @return the integer length of the Queue.
     */
    public int size()
    {
        return size;
    }
    /**
     * Removes all the items from the CircularList
     * @post condition, the size should be zero after operation.
     */
    public void clear()
    {
        Iterator<Item> ite = iterator();
        while (ite.hasNext())
        {
            ite.next();
            ite.remove();
        }
    }
    /**
     * Returns a string representation of the List.
     * @return a string of the list.
     */
    public String toString()
    {
        if (size == 0)
        {
            return "<>";
        }
//        else if (size == 1)
//        {
//            return "<" + head.next().toString() + ">";
//        }
        Iterator<Item> itty = iterator();
        StringBuffer output = new StringBuffer();
        output.append("<");
        while (itty.hasNext())
        {
            output.append(itty.next());
            output.append(", ");
        }
        output.delete(output.length() - 2, output.length());
        output.append(">");
        return output.toString();
    }
    /**
     * Creates a new Iterator Object.
     * @return Iterator  an iterator that works with this CircularList.
     */
    public Iterator<Item> iterator()
    {
        return new CircularIterator();
    }
    /**
     * // -------------------------------------------------------------------------
    /**
     *  Iterator for the CircularList
     *
     *  @author Joe Acanfora
     *  @version Nov 16, 2011
     */
    private class CircularIterator implements Iterator<Item>
    {
        //----------Fields-------------
        private Link<Item> currentPos;
        private boolean calledNext;

        /**
         * Constructor for the Iterator
         */
        public CircularIterator()
        {
            calledNext = false;
            currentPos = head;
        }
        /**
         * See if link has a link following.
         * @return true if link has next, false otherwise.
         */
        public boolean hasNext()
        {
            if (currentPos.equals(tail)
                && head.next().equals(tail))
            {
                return false;
            }
            return true;
        }

        /**
         * Return the next item in the stack.
         * @precondition hasNext() must be called.
         * @return Item  value at the next link.
         */
        public Item next()
        {
            if ((!(this.hasNext())))
            {
                throw new NoSuchElementException("no such element");
            }
            else
            {
                calledNext = true;
                if (currentPos.equals(tail))
                {
                    currentPos = head.next();
                }
                else
                {
                    currentPos = currentPos.next();
                }
                Item currentItem = currentPos.getData();
                return currentItem;
            }

        }
        /**
         * Removes the last element returned by the next method.
         * @precondition next() must be called first.
         */
        public void remove()
        {
            if (!calledNext)
            {
                throw new IllegalStateException(
                    "Must call next() before remove");

            }
            Link<Item> temp = currentPos.previous();
            Link<Item> newAfter = currentPos.next();
            // need to rmove the link previous to this.
            currentPos.split();
            temp.split();
            temp.join(newAfter);
            calledNext = false;
            size--;
        }

    }// end of CircularIterator
}// end of CircularList
